import Flutter
import UIKit
import QCloudCOSXML
import QCloudCore

public class SwiftFlutterTcosPlugin: NSObject, FlutterPlugin, QCloudSignatureProvider, QCloudCredentailFenceQueueDelegate {
  private var credentialFenceQueue:QCloudCredentailFenceQueue?
  private var mBucket: String = ""
  private var mAppID: String = ""
  private var mSignUrl: String = ""
  private var mCookie: String = ""
  private var mRegion: String = ""
  private var mSystemId: UInt = 0;
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "flutter_tcos", binaryMessenger: registrar.messenger())
    let instance = SwiftFlutterTcosPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    switch call.method {
      case "getPlatformVersion":
          result("iOS " + UIDevice.current.systemVersion)
      case "initCosServer":
          initCosServer(call, result: result)
      case "upload":
        upload(call, result: result)
      case "uploadWithName":
        uploadWithName(call, result: result)
      default:
          result (FlutterMethodNotImplemented)
    }
  }

  public func signature(with fileds: QCloudSignatureFields!, request: QCloudBizHTTPRequest!, urlRequest urlRequst: NSMutableURLRequest!, compelete continueBlock: QCloudHTTPAuthentationContinueBlock!) {
        self.credentialFenceQueue?.performAction({ (creator, error) in
            if error != nil {
                continueBlock(nil,error!);
            }else{
                let signature = creator?.signature(forData: urlRequst);
                continueBlock(signature,nil);
            }
        })
  }

  public func fenceQueue(_ queue: QCloudCredentailFenceQueue!, requestCreatorWithContinue continueBlock: QCloudCredentailFenceQueueContinue!) {
    let request: QCloudHTTPRequest = QCloudHTTPRequest.init()
    request.requestSerializer.httpMethod = HTTPMethodPOST
    request.requestSerializer.useCookies = false
    request.requestSerializer.shouldAuthentication = false

    request.requestData.serverURL = self.mSignUrl
    request.requestData.setValue(self.mCookie, forHTTPHeaderField: "authorization")
      request.requestData.setParameter(self.mBucket+"-" + self.mAppID, withKey: "bucket")
    request.requestData.setParameter(self.mRegion, withKey: "region")
    if(mSystemId > 0) {
      request.requestData.setParameter(self.mSystemId, withKey: "systemId")
    }

    request.setConfigureBlock { (_ requestSerializer: QCloudRequestSerializer, _ responseSerializer: QCloudResponseSerializer) in
        requestSerializer.serializerBlocks = [QCloudURLFuseSimple, QCloudURLFuseWithJSONParamters]
        responseSerializer.serializerBlocks = [QCloudAcceptRespnseCodeBlock([200], nil), QCloudResponseJSONSerilizerBlock]
    }

    QCloudHTTPSessionManager.shareClient()?.perform(request, withFinish: { (_ response: Any?, _ error: Error?) in
        if(error != nil) {
            continueBlock(nil, error)
        } else {
            let dic:Dictionary = response! as! Dictionary<String, Any>
            let code = dic["status"] as! Int
            if(code == 0) {
                let data: Dictionary = dic["data"] as! Dictionary<String, Any>
                let credentialData: Dictionary = data["credentials"] as! Dictionary<String, String>
                let cre = QCloudCredential.init();
                cre.secretID = credentialData["tmpSecretId"];
                cre.secretKey = credentialData["tmpSecretKey"];
                cre.token = credentialData["sessionToken"];
                cre.expirationDate = DateFormatter().date(from: "\(data["expiredTime"] as! Int)")
                let auth = QCloudAuthentationV5Creator.init(credential: cre);
                continueBlock(auth,nil);
            } else {
                continueBlock(nil, NSError.init(domain: self.mSignUrl, code: code, userInfo: nil))
            }
        }
    })
  }

  private func initCosServer(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    let args: NSDictionary = call.arguments as! NSDictionary

    mBucket = args["bucket"] as! String
    mAppID = args["appID"] as! String
    mSignUrl = args["signUrl"] as! String
    mCookie = args["cookie"] as! String
    mRegion = args["region"] as! String
    mSystemId = args["systemId"] as! UInt

    let config = QCloudServiceConfiguration.init();
    config.appID = mAppID
    config.signatureProvider = self
    let endPoint = QCloudCOSXMLEndPoint.init()
    endPoint.regionName = mRegion
    endPoint.useHTTPS = false
    config.endpoint = endPoint
    if(QCloudCOSXMLService.hasService(forKey: mRegion)) {
        QCloudCOSXMLService.removeCOSXML(withKey: mRegion)
    }
    QCloudCOSXMLService.registerCOSXML(with: config, withKey: mRegion)
    QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: config)
    self.credentialFenceQueue = QCloudCredentailFenceQueue.init()
    self.credentialFenceQueue?.delegate = self
    result(1)
  }

  private func upload(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    let args: NSDictionary = call.arguments as! NSDictionary
    let originLocalPath: String = args["originLocalPath"] as! String
    let targetPath: String = args["targetPath"] as! String
    
    var index = originLocalPath.lastIndex(of: "/") ?? originLocalPath.startIndex
    if(index != originLocalPath.startIndex) {
        index = originLocalPath.index(after: index)
    }

    let fileName = originLocalPath[index..<originLocalPath.endIndex]
    print(fileName)

    let uploadRequest = QCloudCOSXMLUploadObjectRequest<AnyObject>.init();
    uploadRequest.bucket = mBucket + "-" + mAppID
    uploadRequest.object = targetPath + "\(Int(NSTimeIntervalSince1970))" + fileName
    uploadRequest.body = URL.init(fileURLWithPath: originLocalPath) as AnyObject

    uploadRequest.setFinish { (ret, error) in
    if error != nil{
        DispatchQueue.main.async {
          // Call the desired channel message here.
            result(nil)
        }
    }else{
        DispatchQueue.main.async {
          // Call the desired channel message here.
            result((ret!).location);
        }
    }}

    QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(uploadRequest)
  }

  private func uploadWithName(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    let args: NSDictionary = call.arguments as! NSDictionary
    let originLocalPath: String = args["originLocalPath"] as! String
    let targetPath: String = args["targetPath"] as! String
    
    var index = originLocalPath.lastIndex(of: "/") ?? originLocalPath.startIndex
    if(index != originLocalPath.startIndex) {
        index = originLocalPath.index(after: index)
    }

    let fileName = originLocalPath[index..<originLocalPath.endIndex]
    print(fileName)

    let uploadRequest = QCloudCOSXMLUploadObjectRequest<AnyObject>.init();
    uploadRequest.bucket = mBucket + "-" + mAppID
    uploadRequest.object = targetPath
    uploadRequest.body = URL.init(fileURLWithPath: originLocalPath) as AnyObject

    uploadRequest.setFinish { (ret, error) in
    if error != nil{
        DispatchQueue.main.async {
          // Call the desired channel message here.
            result(nil)
        }
    }else{
        DispatchQueue.main.async {
          // Call the desired channel message here.
            result((ret!).location);
        }
    }}

    QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(uploadRequest)
  }
}
